package com.example.fabric1.controller;

import com.alibaba.fastjson.JSON;

import com.example.fabric1.model.channel.*;
import com.example.fabric1.util.JsonData;
import com.example.fabric1.util.JsonUtil;
import com.example.fabric1.util.ParseUtil;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.ContractException;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.protos.common.Ledger;
import org.hyperledger.fabric.protos.peer.TransactionPackage;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.transaction.TransactionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

@RestController
@Slf4j
@RequestMapping("/api/v1/channel")
public class ChannelController {
    @Resource
    private Contract contract;
    @Autowired
    private Channel channel;

    @GetMapping("/queryTransactionByID")
    public JsonData queryTransactionByID(String txId) throws InvalidArgumentException, ProposalException, IOException {
        BlockInfo blockInfo = channel.queryBlockByTransactionID(txId);
        Transaction transaction = ParseUtil.parseTransactionInfo(blockInfo, txId);
        return JsonData.buildSuccess(transaction);
    }
    @GetMapping("/queryBlockByHash")
    public JsonData queryBlockByHash(@RequestParam("hash") String hash) throws InvalidArgumentException, ProposalException, IOException {
        System.out.println("------------------------");
        byte[] decode = Hex.decode(hash);
        System.out.println(Hex.decode(hash));
        BlockInfo blockInfo = channel.queryBlockByHash(Hex.decode(hash));

        Block block = ParseUtil.parseBlockInfo(blockInfo);
        return JsonData.buildSuccess(block);
    }
    @GetMapping("/queryBlockByTxId")
    public JsonData queryBlockByTxId(@RequestParam("txid") String txId) throws InvalidArgumentException, ProposalException, IOException {
        BlockInfo blockInfo = channel.queryBlockByTransactionID(txId);
        Block block = ParseUtil.parseBlockInfo(blockInfo);
        return JsonData.buildSuccess(block);
    }

    @GetMapping("/queryOtherInfo")
    public JsonData queryOtherInfo()
    {
        OtherInfo otherInfo=new OtherInfo();
        long height = 0;
        try {
            height = channel.queryBlockchainInfo().getHeight();
        } catch (ProposalException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        }
        otherInfo.setHeight(height);
        System.out.println(channel.getName());
        otherInfo.setChannel(channel.getName());
        Collection<Peer> peers = channel.getPeers();

        List<MyPeer> myPeers=new ArrayList<MyPeer>();
        peers.forEach(new Consumer<Peer>() {
            @Override
            public void accept(Peer peer) {
                MyPeer myPeer=new MyPeer();
                myPeer.setPeerName(peer.getName());

                myPeers.add(myPeer);
            }
        });
        otherInfo.setPeers(myPeers);


        return JsonData.buildSuccess(otherInfo);
    }

    @GetMapping("/queryAllBlocks")
    public JsonData queryAllBlocks()  {
        //获取区块链信息
        BlockchainInfo blockchainInfo = null;
        try {
            blockchainInfo = channel.queryBlockchainInfo();
        } catch (ProposalException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        }
        Ledger.BlockchainInfo blockchainInfo1 = blockchainInfo.getBlockchainInfo();
        long height = blockchainInfo.getHeight();
        byte[] currentBlockHash = blockchainInfo.getCurrentBlockHash();
        byte[] previousBlockHash = blockchainInfo.getPreviousBlockHash();
        //获取当前区块信息
        BlockInfo blockInfo = null;
        try {
            blockInfo = channel.queryBlockByHash(currentBlockHash);
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (ProposalException e) {
            e.printStackTrace();
        }
        Block block = null;
        try {
            block = ParseUtil.parseBlockInfo(blockInfo);
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //保存全部区块
        List<Block> blocks = new LinkedList<>();
        blocks.add(block);
        for (long i = 0; i < height; i++) {
            if(previousBlockHash.length==0)
            {
                break;
            }
            //获取上一个区块信息
            BlockInfo blockInfo1 = null;
            try {
                blockInfo1 = channel.queryBlockByHash(previousBlockHash);
            } catch (InvalidArgumentException e) {
                e.printStackTrace();
            } catch (ProposalException e) {
                e.printStackTrace();
            }
            try {
                block = ParseUtil.parseBlockInfo(blockInfo1);
            } catch (InvalidArgumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            blocks.add(block);

            previousBlockHash = blockInfo1.getPreviousHash();
        }
        return JsonData.buildSuccess(blocks);

    }


    @GetMapping("/queryHeight")
    public JsonData queryBlockByTxId() throws InvalidArgumentException, ProposalException, IOException {
        long height = channel.queryBlockchainInfo().getHeight();

        return JsonData.buildSuccess(height);
    }
    @PostMapping("/addTrace")
    public JsonData addTrace(@RequestBody AddTrace addTrace) throws ContractException, InterruptedException, TimeoutException {

        TransactionContext transactionContext = channel.newTransactionContext();

        byte[] txid = contract.submitTransaction("addTrace", addTrace.getTraceCode(),addTrace.getKey(),addTrace.getValue());


        return JsonData.buildSuccess(new String(txid));
    }
    @PostMapping("/addFinalTrace")
    public JsonData addFinalTrace(@RequestBody AddFinalTrace addFinalTrace) throws ContractException, InterruptedException, TimeoutException {

        TransactionContext transactionContext = channel.newTransactionContext();

        byte[] txid = contract.submitTransaction("addFinalTrace", addFinalTrace.getTraceCode(),addFinalTrace.getValue());


        return JsonData.buildSuccess(new String(txid));
    }
    @GetMapping("/queryTCInfo")
    public JsonData testBlock(@RequestParam("traceCode") String traceCode) throws ContractException, InterruptedException, TimeoutException {
        TransactionContext transactionContext = channel.newTransactionContext();
        byte[] findAlls = contract.submitTransaction("findAll", traceCode);
        return JsonData.buildSuccess(new String(findAlls));
    }
}

